package Game.Objects.Creatures;

import java.util.Random;

import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import Game.GameHelper;
import Game.Items.Potions.GISmallHealthPotion;
import Game.MapBlock.EMapBlockType;
import Game.Objects.GOPlayer;
import Game.Objects.GameObject;
import Game.Objects.ObjectManager;
import GameMath.GPoint;
import GameMath.GRandom;
import GameMath.GSize;

/** Slime creature class
 * @author Aikidos
 */
public class GOCSlime extends GOCreature {

	/** Friend slime (follow slime) */
	private GameObject _friendSlime = null;
	
	/** Radius for find other slime */
	private int _findOtherSlimeRadius = 7;
	
	/** Walk radius around other slime */
	private int _walkAroundOtherSlimeRadius = 4;
	
	/** Range of aggression */
	private int _rangeOfAggression;
	
	public GOCSlime(ObjectManager objectManager) throws SlickException {
		super(objectManager, "Slime");
		
		setSprite(new Image("res/gfx/creatures/slime.png"));
		
		Type = EGameObjectType.Enemy;
		
		_rangeOfAggression = 1;
		
		MaxHealth = 7;
		setHealth(MaxHealth);
		
		Magic = 1;
		Experience = 1;
		
		MinDamage = 1;
		MaxDamage = 1;
		
		// Add other items
		getInventory().addItem(new GISmallHealthPotion(), 30);
	}

	@Override
	public void step() throws SlickException {
		super.step();
		
		boolean goToPlayer = false;
		boolean goToAlly = false;
		
		if ((_friendSlime != null) && _friendSlime.isDestroyed())
			_friendSlime = null;
		
		// Find player
		goToPlayer = stepFindPlayer();
		
		// Else find ally
		if (!goToPlayer) {
			goToAlly = stepFindAlly();
		}
		
		// Else go to friend slime
		if (!goToPlayer && !goToAlly && (_friendSlime != null)) {
			stepGoToFriendSlime();
		}
		
		// Else find other slime
		if (!goToPlayer && !goToAlly && (_friendSlime == null)) {
			stepFindFriendSlime();
		}
		
		// Else go to random coordinate
		if (!goToPlayer && (_friendSlime == null) && !goToAlly && (getWalkPath().size() == 0)) {		
			stepGoToRandomCoord();
		}
		
		walk();
	}
	
	@Override
	public boolean onCollision(GameObject other, boolean moveOn) {
		if (other.isCreature())
		{
			GOCreature creature = (GOCreature) other;
			if (creature.Type == EGameObjectType.Ally)
			{
				if (moveOn) attack(other);
				return false;
			}
		}
		else if (other.isPlayer())
		{
			if (moveOn) attack(other);
			
			return false;
		}
		
		return true;
	}
	
	/** Find player and go to him
	 * @return true if player is found
	 */
	private boolean stepFindPlayer() {
		GOPlayer player = _objectManager.getPlayer();
		int distance = _objectManager.getLevel().getMap()
				.getDistance(getCoord(), player.getCoord());
		if ((distance != -1) && (distance <= _rangeOfAggression)) {
			go(player.getCoord());
			return true;
		}
		
		return false;
	}
	
	/** Find ally mob and go to him
	 * @return true if ally mob is found
	 */
	private boolean stepFindAlly() {
		for (GameObject gameObject : _objectManager.getObjects()) {
			if (gameObject.isCreature() && (((GOCreature) gameObject).Type == EGameObjectType.Ally)) {
				int distance = _objectManager.getLevel().getMap().getDistance(getCoord(), gameObject.getCoord());
				if ((distance != -1) && (distance <= _rangeOfAggression)) {
					go(gameObject.getCoord());
					return true;
				}
			}
		}
		
		return false;
	}
	
	/** Go to friend slime */
	private void stepGoToFriendSlime() {
		GSize mapSize = _objectManager.getLevel().getMap().getSize();
		
		// Go to random position around other slime
		GPoint p = new GPoint();
		while (true) {
			p = new GPoint(GRandom.nextInt(_friendSlime.getCoord().x
					- _walkAroundOtherSlimeRadius, _friendSlime.getCoord().x
					+ _walkAroundOtherSlimeRadius), GRandom.nextInt(
					_friendSlime.getCoord().y - _walkAroundOtherSlimeRadius,
					_friendSlime.getCoord().y + _walkAroundOtherSlimeRadius));

			if ((p.x >= 0) && (p.x < mapSize.width) && (p.y >= 0)
					&& (p.y < mapSize.height)) {
				if (_objectManager.getLevel().getMap().getBlocks()[p.x][p.y].Type == EMapBlockType.Floor) {
					int d = _objectManager.getLevel().getMap()
							.getDistance(_friendSlime.getCoord(), p);
					if ((d != -1) && (d <= _walkAroundOtherSlimeRadius))
						break;
				}
			}
		}

		go(p);
	}
	
	/** Find friend slime */
	private void stepFindFriendSlime() {
		GameObject[] gameObjects = _objectManager.getObjectsByClass("Game.Objects.Creatures.GOCSlime");
		for (GameObject gameObject : gameObjects) {
			if (gameObject != this) {
				int distance = _objectManager.getLevel().getMap().getDistance(getCoord(), gameObject.getCoord());
				if ((distance != -1) && (distance <= _findOtherSlimeRadius)) {
					_friendSlime = gameObject;
					return;
				}
			}
		}
	}
	
	/** Go to random coordinates */
	private void stepGoToRandomCoord() {
		GSize mapSize = _objectManager.getLevel().getMap().getSize();
		
		Random rnd = GameHelper.getRandom();
		
		GPoint p = new GPoint(
				rnd.nextInt(mapSize.width), 
				rnd.nextInt(mapSize.height));
		
		while (_objectManager.getLevel().getMap().getBlocks()[p.x][p.y].Type != EMapBlockType.Floor)
			p = new GPoint(
					rnd.nextInt(mapSize.width), 
					rnd.nextInt(mapSize.height));
		
		go(p);
	}
	
}
